package impl

import (
	"errors"
	"github.com/gorilla/websocket"
	"sync"
)

type Connection struct {
	//websocket的长连接
	wsConn *websocket.Conn
	//inChan放我们读到的消息
	inChan chan []byte
	//outChan我们发出去的消息,也是一条一条的消息
	outChan chan []byte
	closeChan chan byte

	mutex sync.Mutex
	isClosed bool
}
//定义API,websocket长连接做一个封装,返回一个连接指针和错误
func InitConnection(wsConn *websocket.Conn)(conn *Connection, err error){
	conn = &Connection{
		wsConn:wsConn,
		//给一个1000容量,满了就放不进去
		inChan:make(chan []byte, 1000),
		outChan:make(chan []byte,1000),
		closeChan:make(chan byte, 1),
	}
	//启动一个读协程
	go conn.readLoop()
	//启动写协程
	go conn.writeLoop()

    return
}
//API 消息 返回值是一个消息和一个错误
func(conn *Connection) ReadMessage() (data []byte,err error){
	select {
	case data = <-conn.inChan:
	case <- conn.closeChan:
		err=errors.New("connection is closed")
	}

	return
}
//发送API
func(conn *Connection) WriteMessage(data []byte) (err error){
	select {
	case conn.outChan <- data:
	case <- conn.closeChan:
		err=errors.New("connection is closed")
	}

	return
}
//关闭API
func(conn *Connection)Close(){
	//线程安全的,可重入的
	conn.wsConn.Close()

	//这行代码只执行一次
	//锁住这个链接
	conn.mutex.Lock()
	//判断这个标记是否被关闭过
	if !conn.isClosed{
		close(conn.closeChan)
		conn.isClosed = true
	}
	//释放锁
	conn.mutex.Unlock()
}
//内部实现,不断的读取队列消息, 读取到了放到队列里
func(conn *Connection)readLoop(){
	var(
		data []byte
		err  error
	)
	if _,data,err = conn.wsConn.ReadMessage();err!=nil {
		goto ERR
	}
	//堵塞在这里,等待inChain有空闲的位置
	select {
	case conn.inChan <- data:
	case <- conn.closeChan:
		//conn.closeChan关闭的时候
		goto ERR
	}

	conn.inChan <- data
ERR:
 	conn.Close()
}
func(conn *Connection)writeLoop(){
	var(
		data []byte
		err error
	)

	for{
		select {
		case data = <- conn.outChan:
		case <- conn.closeChan:
			goto ERR
		}

		if err = conn.wsConn.WriteMessage(websocket.TextMessage,data);err!=nil{
			goto ERR
		}
	}
ERR:
	conn.Close()
}